#include<stdio.h>
#include<unistd.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

#define NUM 1024
#define ARGC 64
#define SPLT " "

typedef enum REDIRECT
{
    REDIR_INPUT = 0,
    REDIR_OUTPUT,
    REDIR_APPEND,
    REDIR_NONE
}REDIRECT;

void ShowEnv()
{
    extern char** environ;
    int i = 0;
    for(; environ[i]; i++)
        printf("%d:%s\n",i,environ[i]);

}
void DebugCommand(char com[])
{
    printf("%s\n",com);
}

int SplitCommand(char command[],char* argv[])
{
    if(command[0] == '\0' )
        return -1;
    argv[0] =  strtok(command,SPLT);
    int i = 1;
    while((argv[i++] = strtok(NULL,SPLT)));
    argv[i] = NULL;
    return 0;
}
void DebugArgv(char* argv[])
{
    int i = 0;
    for(; argv[i]; i++)
    {
        printf("%d -- %s\n",i,argv[i]);
    }
}
char*  check(char command[] ,REDIRECT* REDIR_val)
{   
    int i = 0;
    int end = 0; 
    // > -- 1  >> -  2  <  4    
    for(;i < strlen(command) ;i++)
    {
        if(command[i] == '>')
        {
            if(command[i+1] == '>')
            {
                command[i] = '\0';
                *REDIR_val = REDIR_APPEND;
                end = i+1;
            }
            else
            {
                command[i] = '\0';
                *REDIR_val = REDIR_OUTPUT;
                end = i;
            }
        }
        if(command[i] == '<')
        {
            command[i] = '\0';
            *REDIR_val = REDIR_INPUT;
            end = i;
        }
    }
    if(*REDIR_val != REDIR_NONE)
    {

        char* filename = strtok(&command[end+1]," ");
        return filename;
    }
    return NULL;
}
int main()
{
    char env_map[32][64];
    int env_i = 0;
    int exit_code = -1; //退出码 
    while(1)
    {
        REDIRECT REDIR_val = REDIR_NONE;
        printf("[lin@mybash mybash]#");
      //fflush(stdout);
      //sleep(1);
        char command[NUM] = { 0 };
        char* ptrf = fgets(command,sizeof(command),stdin);
        assert(ptrf);
        (void)ptrf;
        command[strlen(command)-1] = '\0';
       // DebugCommand(command);
        //sleep(2);
        char* filename = check(command,&REDIR_val);
        char* argv[ARGC] = {NULL};
        int ret =  SplitCommand(command,argv);
        if(ret == -1)
            continue;
       // DebugArgv(argv);
        //完成内建命令的设置：诸如cd，export，env,echo，即需要在自己的bash手搓这些函数
        if(strcmp(argv[0],"cd") == 0)
        {
            if(argv[1] != NULL) 
                chdir(argv[1]);//更改路劲
            continue;
        }
        else if(strcmp(argv[0],"export") == 0)
        {
            //环境变量不能存放在随时变化的缓冲区内部，必须自己维护在一个稳定的缓冲区中
            //也就是说，当要导入环境变量时，是不能使用command,argv这两个缓冲区，需要另外维护一个
            if(argv[1] != NULL)
            {
                strcpy(env_map[env_i],argv[1]); 
                putenv(env_map[env_i++]);//导入环境变量
            }
            continue;
        }
        else if(strcmp(argv[0],"env") == 0 )
        {
            ShowEnv();
            continue;
        }
        else if(strcmp(argv[0],"echo") == 0 )
        {
            if(argv[1][0] == '$')
            {
                if(argv[1][1] == '?')//打印退出码
                {
                    printf("%d\n",exit_code); 
                }
                else//打印环境变量的值
                {
                     const char* target_env = NULL;
                     target_env = getenv(argv[1]+1);//获取环境变量的值
                     if(target_env != NULL)
                          printf("%s=%s\n",argv[1]+1,target_env);
                }
            }
            else
            {
                printf("%s\n",argv[1]);
            }
            continue;
        }
        //将ls配置上颜色
        if(strcmp(argv[0],"ls") == 0)
        {
            int pos = 0;
            while(argv[pos]) pos++;
            argv[pos++] =(char*)"--color=auto";
        }
         pid_t id  =  fork();
         if(id == -1)
             continue;
         if(id == 0)
         {
              if(REDIR_val != REDIR_NONE)
              {
                  //1.open file 
                  //redirect
                  int RE_flag = 0;
                  if(REDIR_val == REDIR_INPUT)
                  {
                      RE_flag |= O_RDONLY;

                  }
                  else if(REDIR_val == REDIR_OUTPUT)
                  {
                      RE_flag = (O_CREAT | O_WRONLY | O_TRUNC );
                  }
                  else if(REDIR_val == REDIR_APPEND)
                  {
                      RE_flag = (O_CREAT | O_WRONLY | O_APPEND);
                  }
                  int fd = open(filename ,RE_flag ,0666);
                  if(REDIR_val != REDIR_INPUT)
                  {
                      printf("dup(fd,1)\n");
                      dup2(fd,1);
                  }  
                  else
                  {
                      printf("dup(fd,0)\n");
                      dup2(fd,0);
                  }
              }
              execvp(argv[0],argv);
              exit(1);
         }
         int status = 0;
         pid_t ret_id =  waitpid(id,&status,0);//阻塞等待
         if( ret_id > 0 )
         {
              exit_code = WEXITSTATUS(status);
         }
      //   else
      //   {
      //        int status = 0;
      //        while(1)
      //        {

      //            int ret_w =  waitpid(id,&status,WNOHANG);
      //            if(ret_w < 0)
      //            {
      //                  printf("我是父进程，等待子进程失败\n");
      //            }
      //            else if(ret_w == 0)//子进程还在执行
      //            {
      //                printf("我是父进程，我正在做其他事情 ret_w: %d\n",ret_w);
      //                sleep(1);

      //            }
      //            else
      //            {
      //                if(WIFEXITED(status))
      //                {
      //                    printf("我是父进程，成功等待子进程：exit_code: %d \n",WEXITSTATUS(status));
      //                    break;
      //                }
      //                else
      //                {
      //                    printf("我是父进程，成功等待子进程：exit_signal: %d\n",status & 0x7F);
      //                    break;
      //                }
      //            }
      //        }
      //   }
    }
    return 0;
}
